// Package adapter 提供各种音频播放器适配器
package adapter

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/audioplayer"
	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"go.uber.org/zap"
)

// MP3信息结构
type mp3Info struct {
	duration float64 // 总时长（秒）
}

// NewMPG123Player 创建一个基于mpg123的播放器实例
func NewMPG123Player(config *audioplayer.Config) (audioplayer.AudioPlayer, error) {
	return NewMPG123Adapter(config)
}

// MPG123Adapter 实现了基于mpg123命令行工具的音频播放适配器
type MPG123Adapter struct {
	mutex              sync.Mutex
	cmd                *exec.Cmd
	stdin              io.WriteCloser             // 用于向mpg123发送命令
	stdout             io.ReadCloser              // 用于读取mpg123输出
	status             audioplayer.PlaybackStatus // "playing", "paused", "stopped"
	volume             float64                    // 音量 0.0-1.0
	position           float64                    // 当前播放位置(秒)
	duration           float64                    // 总时长(秒)
	source             *audioplayer.AudioSource
	playlist           []*audioplayer.AudioSource
	playlistMutex      sync.RWMutex
	supportedFormats   []audioplayer.AudioFormat
	config             *audioplayer.Config
	startTime          time.Time
	eventHandlers      map[audioplayer.PlaybackEventType][]audioplayer.PlaybackEventHandler
	stopChan           chan struct{}  // 用于停止后台监听
	frameRegex         *regexp.Regexp // 用于解析mpg123输出的帧信息
	lastPositionUpdate time.Time
	currentFileName    string
	currentFile        string
	stderr             io.ReadCloser // 用于读取mpg123标准错误输出
}

// NewMPG123Adapter 创建一个新的mpg123适配器实例
func NewMPG123Adapter(config *audioplayer.Config) (*MPG123Adapter, error) {
	// 检查mpg123命令是否存在
	mpg123Path := config.PlayerPath
	if mpg123Path == "" {
		mpg123Path = "mpg123"
	}

	_, err := exec.LookPath(mpg123Path)
	if err != nil {
		return nil, fmt.Errorf("mpg123命令不存在: %v", err)
	}

	// 创建并初始化适配器
	adapter := &MPG123Adapter{
		status:             audioplayer.StatusStopped,
		volume:             config.DefaultVolume,
		position:           0,
		duration:           0,
		source:             nil,
		playlist:           make([]*audioplayer.AudioSource, 0),
		supportedFormats:   []audioplayer.AudioFormat{audioplayer.FormatMP3, audioplayer.FormatWAV, audioplayer.FormatOGG},
		config:             config,
		eventHandlers:      make(map[audioplayer.PlaybackEventType][]audioplayer.PlaybackEventHandler),
		stopChan:           make(chan struct{}),
		frameRegex:         regexp.MustCompile(`@F (\d+) (\d+) (\d+\.\d+) (\d+\.\d+)`),
		lastPositionUpdate: time.Now(), // 初始化位置更新时间
	}

	return adapter, nil
}

// 启动mpg123进程和监听
func (m *MPG123Adapter) startMPG123() error {
	mpg123Path := m.config.PlayerPath
	if mpg123Path == "" {
		mpg123Path = "mpg123"
	}

	// 启动mpg123的远程控制模式
	m.cmd = exec.Command(mpg123Path, "-R", "--verbose")

	logger.SystemInfo("启动mpg123命令",
		zap.String("command", mpg123Path),
		zap.String("args", "-R --verbose"))

	// 获取标准输入输出
	stdin, err := m.cmd.StdinPipe()
	if err != nil {
		return fmt.Errorf("无法获取mpg123标准输入: %v", err)
	}
	m.stdin = stdin

	stdout, err := m.cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("无法获取mpg123标准输出: %v", err)
	}
	m.stdout = stdout

	// 获取标准错误
	stderr, err := m.cmd.StderrPipe()
	if err != nil {
		logger.SystemWarn("无法获取mpg123标准错误输出", zap.Error(err))
	} else {
		m.stderr = stderr
		// 启动错误监控
		go m.monitorError()
	}

	// 启动命令
	err = m.cmd.Start()
	if err != nil {
		return fmt.Errorf("启动mpg123失败: %v", err)
	}

	// 启动后台监听goroutine
	go m.monitorOutput()

	logger.SystemInfo("mpg123进程已启动")

	return nil
}

// 监控mpg123的输出
func (m *MPG123Adapter) monitorOutput() {
	if m.stdout == nil {
		logger.SystemError("标准输出流为空，无法监控")
		return
	}

	logger.SystemInfo("开始监控mpg123输出")
	defer logger.SystemInfo("停止监控mpg123输出")

	// 输出一些基本信息，帮助确认监控启动了
	logger.SystemInfo("mpg123输出监控初始状态",
		zap.String("status", string(m.status)),
		zap.Float64("position", m.position),
		zap.Float64("duration", m.duration),
		zap.Bool("hasSource", m.source != nil))

	scanner := bufio.NewScanner(m.stdout)
	// 使用更大的缓冲区，避免长行被截断
	buf := make([]byte, 64*1024)
	scanner.Buffer(buf, len(buf))

	// 帧计数器，用于控制处理频率
	frameCounter := 0
	linesProcessed := 0

	// 创建一个通道来接收扫描到的行
	lineCh := make(chan string, 100)

	// 启动goroutine读取stdout
	go func() {
		for scanner.Scan() {
			select {
			case lineCh <- scanner.Text():
				// 行已发送到通道
			case <-m.stopChan:
				close(lineCh)
				return
			}
		}

		if err := scanner.Err(); err != nil {
			logger.SystemError("读取mpg123输出时出错", zap.Error(err))
		}

		close(lineCh)
	}()

	// 主循环处理从通道接收的行
	for line := range lineCh {
		linesProcessed++

		upperCase := strings.ToLower(line)

		// 如果检测到ID3v2标签信息
		if strings.Contains(upperCase, "ID3V2.") {
			m.handleID3Info(line)
			// 检查歌曲名是否已更新到播放源
			if m.source != nil && m.currentFileName != "" {
				m.mutex.Lock()
				// 确保当前文件名被正确设置
				if m.source.Name != m.currentFileName {
					m.source.Name = m.currentFileName
					logger.SystemDebug("已同步歌曲名称到播放源",
						zap.String("fileName", m.currentFileName))
				}
				m.mutex.Unlock()
			}
			continue // 处理完ID3标签后继续下一行
		}

		if line == "@P 0" ||
			strings.Contains(upperCase, "finished") ||
			strings.Contains(upperCase, "end") ||
			strings.Contains(upperCase, "complete") {

			logger.SystemInfo("检测到音频播放完成", zap.String("line", line))
			m.mutex.Lock()
			m.status = audioplayer.StatusStopped
			m.mutex.Unlock()
			m.triggerEvent(audioplayer.EventPlaybackCompleted) // 触发播放完成事件

			continue
		}

		// 检查帧信息（@F 行）更新播放位置
		if strings.HasPrefix(line, "@F") {
			logger.SystemDebug("检测到帧信息", zap.String("line", line))
			frameCounter++

			// 每10帧处理一次位置更新，减少处理频率
			if frameCounter%10 != 0 {
				continue
			}

			if m.frameRegex == nil {
				m.frameRegex = regexp.MustCompile(`@F (\d+) (\d+) (\d+\.\d+) (\d+\.\d+)`)
			}

			matches := m.frameRegex.FindStringSubmatch(line)
			if len(matches) >= 5 {
				current, _ := strconv.Atoi(matches[1])                 // 当前帧
				remaining, _ := strconv.Atoi(matches[2])               // 剩余帧（非总帧）
				elapsedTime, _ := strconv.ParseFloat(matches[3], 64)   // 已播放时间
				remainingTime, _ := strconv.ParseFloat(matches[4], 64) // 剩余时间（非总时长）

				// 计算总帧数和总时长
				totalFrames := current + remaining
				totalTime := elapsedTime + remainingTime

				logger.SystemDebug("解析帧信息",
					zap.Int("current", current),
					zap.Int("remaining", remaining),
					zap.Int("totalFrames", totalFrames),
					zap.Float64("elapsedTime", elapsedTime),
					zap.Float64("remainingTime", remainingTime),
					zap.Float64("totalTime", totalTime),
					zap.Int("frameCounter", frameCounter))

				if totalFrames > 0 && totalTime > 0 {

					// 根据帧信息更新时长
					if m.duration <= 0 || m.duration > totalTime*1.5 || m.duration < totalTime*0.5 {
						// 当前时长为空，或者与帧信息提供的时长差异过大（超过50%），才更新
						m.duration = totalTime
					}

					// 直接使用mpg123提供的已播放时间作为当前位置
					m.position = elapsedTime

					// 确保位置不超过时长
					if m.position > m.duration {
						logger.SystemWarn("位置超过时长，进行修正",
							zap.Float64("rawPosition", m.position),
							zap.Float64("duration", m.duration))
						m.duration = m.position
					}

					m.triggerPositionChanged(m.position)
				} else {
					logger.SystemWarn("帧信息异常：无法计算总帧数或总时间",
						zap.String("line", line),
						zap.Int("current", current),
						zap.Int("remaining", remaining),
						zap.Float64("elapsedTime", elapsedTime),
						zap.Float64("remainingTime", remainingTime))
				}
			} else {
				logger.SystemWarn("帧信息格式异常", zap.String("line", line))
			}
		}
	}

	logger.SystemInfo("mpg123输出监控结束",
		zap.Int("totalLinesProcessed", linesProcessed),
		zap.Int("totalFramesProcessed", frameCounter))
}

// handleID3Info 处理ID3v2标签信息
func (m *MPG123Adapter) handleID3Info(info string) {
	// 不再尝试解析ID3标签，直接使用文件名
	if m.source != nil && m.source.Path != "" {
		// 从文件路径获取文件名
		parts := strings.Split(m.source.Path, "/")
		fileName := parts[len(parts)-1]

		// 记录使用文件名作为曲目信息
		logger.SystemInfo("使用文件名作为曲目信息，避免ID3标签乱码",
			zap.String("fileName", fileName),
			zap.String("originalPath", m.source.Path))

		// 更新当前文件名和源信息
		m.mutex.Lock()
		m.currentFileName = fileName
		m.source.Name = fileName
		m.mutex.Unlock()
	}

	// 仍然记录原始ID3标签信息，但仅用于调试
	match := regexp.MustCompile(`ID3v2\.([^:]+):(.+)`).FindStringSubmatch(info)
	if len(match) >= 3 {
		tag := match[1]   // 例如 "title"
		value := match[2] // 例如 "歌曲名称"

		// 仅记录日志，不使用这些值
		logger.SystemDebug("收到ID3标签信息（仅记录不使用）",
			zap.String("tag", tag),
			zap.String("value", value))
	}
}

// 触发事件
func (m *MPG123Adapter) triggerEvent(eventType audioplayer.PlaybackEventType) {
	// 创建事件对象
	event := audioplayer.PlaybackEvent{
		Type:      eventType,
		Timestamp: time.Now(),
		Info:      m.getPlaybackInfo(),
	}

	// 获取对应的处理器列表
	handlers, exists := m.eventHandlers[eventType]
	if !exists || len(handlers) == 0 {
		return
	}

	// 异步调用所有处理器
	for _, handler := range handlers {
		go func(h audioplayer.PlaybackEventHandler) {
			defer func() {
				if r := recover(); r != nil {
					logger.SystemError("事件处理器异常", zap.Any("panic", r))
				}
			}()
			h(event)
		}(handler)
	}
}

// triggerPositionChanged 触发位置变更事件，但限制频率
func (m *MPG123Adapter) triggerPositionChanged(position float64) {
	now := time.Now()

	// 详细日志，但放在Debug级别避免过多输出
	logger.SystemDebug("尝试触发位置变更事件",
		zap.Float64("position", position),
		zap.Float64("duration", m.duration),
		zap.Time("lastUpdate", m.lastPositionUpdate),
		zap.Duration("timeSinceLastUpdate", now.Sub(m.lastPositionUpdate)))

	// 减少更新频率，每秒最多更新一次
	if now.Sub(m.lastPositionUpdate) < 1*time.Second {
		return // 距离上次更新不足1秒，跳过
	}

	m.lastPositionUpdate = now

	// 创建包含当前位置的事件对象
	event := audioplayer.PlaybackEvent{
		Type:      audioplayer.EventPositionChanged,
		Timestamp: now,
		Info:      m.getPlaybackInfo(),
	}
	// 确保使用最新的位置值，并验证它不超过时长
	if position > m.duration && m.duration > 0 {
		position = m.duration
	}
	event.Info.Position = position

	// 触发事件处理器
	handlers, exists := m.eventHandlers[audioplayer.EventPositionChanged]
	if !exists || len(handlers) == 0 {
		logger.SystemDebug("没有注册位置变更事件处理器，无法触发更新")
		return
	}

	logger.SystemDebug("触发位置变更事件",
		zap.Float64("position", position),
		zap.Int("handlerCount", len(handlers)))

	// 异步调用所有处理器
	for _, handler := range handlers {
		go func(h audioplayer.PlaybackEventHandler) {
			defer func() {
				if r := recover(); r != nil {
					logger.SystemError("事件处理器异常", zap.Any("panic", r))
				}
			}()
			h(event)
		}(handler)
	}
}

// 向mpg123发送命令
func (m *MPG123Adapter) sendCommand(cmd string) error {
	if m.stdin == nil {
		return fmt.Errorf("mpg123命令未启动")
	}

	_, err := fmt.Fprintf(m.stdin, "%s\n", cmd)
	if err != nil {
		return fmt.Errorf("发送命令失败: %v", err)
	}

	return nil
}

// Play 播放指定的音频文件
func (m *MPG123Adapter) Play(ctx context.Context, source audioplayer.AudioSource) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	logger.SystemInfo("准备播放文件",
		zap.String("path", source.Path),
		zap.String("name", source.Name))

	// 如果mpg123未启动，先启动它
	if m.cmd == nil {
		logger.SystemInfo("mpg123进程未启动，正在初始化...")
		err := m.startMPG123()
		if err != nil {
			logger.SystemError("启动mpg123失败", zap.Error(err))
			return err
		}
	}

	// 复制AudioSource以确保不会被外部修改
	sourceCopy := source
	m.source = &sourceCopy

	// 保存当前文件路径
	m.currentFile = source.Path

	// 直接从文件路径获取文件名（忽略所有ID3标签）
	parts := strings.Split(source.Path, "/")
	fileName := parts[len(parts)-1]

	// 设置当前文件名和源信息，保留文件后缀
	m.currentFileName = fileName
	m.source.Name = fileName

	logger.SystemInfo("设置播放文件名",
		zap.String("fileName", fileName),
		zap.String("originalPath", source.Path))

	// 重置计时和状态
	m.position = 0
	m.startTime = time.Now()

	// 重置时长信息，准备重新获取
	m.duration = 0

	// 检查文件是否存在
	fileInfo, err := os.Stat(source.Path)
	if os.IsNotExist(err) {
		return fmt.Errorf("文件不存在: %s", source.Path)
	} else if err != nil {
		return fmt.Errorf("检查文件状态失败: %v", err)
	}

	logger.SystemInfo("文件状态检查",
		zap.String("path", source.Path),
		zap.Int64("size", fileInfo.Size()),
		zap.Time("modTime", fileInfo.ModTime()))

	// 获取文件时长，尝试多种方法
	info, err := getMP3Info(source.Path)
	if err == nil && info.duration > 0 {
		m.duration = info.duration
		logger.SystemInfo("成功获取音频时长",
			zap.String("file", source.Path),
			zap.Float64("duration", m.duration))
	} else {
		logger.SystemWarn("预先获取音频时长失败，将尝试从播放过程中推断",
			zap.String("file", source.Path),
			zap.Error(err))
	}

	// 设置状态为播放中
	m.status = audioplayer.StatusPlaying

	// 发送加载命令到mpg123
	loadCmd := fmt.Sprintf("LOAD %s", source.Path)
	logger.SystemDebug("发送命令到mpg123", zap.String("command", loadCmd))

	err = m.sendCommand(loadCmd)
	if err != nil {
		logger.SystemError("发送LOAD命令到mpg123失败", zap.Error(err))
		m.status = audioplayer.StatusError
		return err
	}

	// 确认播放已开始
	logger.SystemInfo("发送播放命令成功，等待播放开始")

	// 主动触发开始事件
	m.triggerEvent(audioplayer.EventPlaybackStarted)

	logger.SystemInfo("开始播放音频",
		zap.String("path", source.Path),
		zap.String("name", m.currentFileName),
		zap.Float64("duration", m.duration))

	return nil
}

// Pause 暂停播放
func (m *MPG123Adapter) Pause(ctx context.Context) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.status != audioplayer.StatusPlaying {
		return fmt.Errorf("没有可暂停的活跃播放")
	}

	err := m.sendCommand("PAUSE")
	if err != nil {
		return err
	}

	m.status = audioplayer.StatusPaused
	m.triggerEvent(audioplayer.EventPlaybackPaused)
	// 状态更新将通过输出监听器处理
	return nil
}

// Resume 从暂停状态恢复播放
func (m *MPG123Adapter) Resume(ctx context.Context) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.status != audioplayer.StatusPaused {
		return fmt.Errorf("没有可恢复的暂停播放")
	}

	err := m.sendCommand("PAUSE") // mpg123使用相同的PAUSE命令来切换暂停/播放状态
	if err != nil {
		return err
	}

	m.status = audioplayer.StatusPlaying
	m.triggerEvent(audioplayer.EventPlaybackResumed)
	// 状态更新将通过输出监听器处理
	return nil
}

// Stop 停止播放
func (m *MPG123Adapter) Stop(ctx context.Context) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.cmd == nil {
		return nil // 已经停止
	}

	err := m.sendCommand("STOP")
	if err != nil {
		return err
	}

	m.status = audioplayer.StatusStopped
	m.triggerEvent(audioplayer.EventPlaybackStopped)
	// 状态更新将通过输出监听器处理
	return nil
}

// IsPlaying 返回当前是否正在播放
func (m *MPG123Adapter) IsPlaying() bool {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	return m.status == audioplayer.StatusPlaying
}

// Seek 跳转到指定位置
func (m *MPG123Adapter) Seek(ctx context.Context, position float64) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.status == audioplayer.StatusStopped || m.source == nil {
		return fmt.Errorf("没有正在播放的文件")
	}

	// 确保position不超出文件长度
	if position > m.duration {
		position = m.duration
	}
	if position < 0 {
		position = 0
	}

	// 计算帧位置（假设的帧率，可能需要根据实际情况调整）
	framePosition := int(position / m.duration * 100)
	err := m.sendCommand(fmt.Sprintf("JUMP %d%%", framePosition))
	if err != nil {
		return err
	}

	m.position = position
	return nil
}

// GetPosition 获取当前播放位置（秒）
func (m *MPG123Adapter) GetPosition() float64 {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	position := m.position

	// 记录位置信息
	logger.SystemDebug("获取播放位置",
		zap.Float64("position", position),
		zap.String("status", string(m.status)))

	return position
}

// GetDuration 获取当前音频文件的总时长（秒）
func (m *MPG123Adapter) GetDuration() float64 {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	// 检查时长是否有效，如果无效则尝试获取
	if m.duration <= 0 && m.source != nil {
		// 已尝试从播放中获取时长，但仍然失败，再次使用文件方法获取
		logger.SystemDebug("尝试重新获取音频时长",
			zap.String("file", m.source.Path),
			zap.Float64("currentDuration", m.duration))

		info, err := getMP3Info(m.source.Path)
		if err == nil && info.duration > 0 {
			m.duration = info.duration
			logger.SystemInfo("成功重新获取音频时长",
				zap.Float64("duration", m.duration),
				zap.String("file", m.source.Path))
		}
	}

	// 记录时长信息
	logger.SystemDebug("获取音频时长",
		zap.Float64("duration", m.duration))

	return m.duration
}

// SetVolume 设置音量（0.0-1.0）
func (m *MPG123Adapter) SetVolume(volume float64) error {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	// 确保音量在有效范围内
	if volume < 0 {
		volume = 0
	} else if volume > 1.0 {
		volume = 1.0
	}

	// mpg123的音量范围是0-100
	mpg123Volume := int(volume * 100)
	err := m.sendCommand(fmt.Sprintf("VOLUME %d", mpg123Volume))
	if err != nil {
		return err
	}

	m.volume = volume
	return nil
}

// GetVolume 获取当前音量
func (m *MPG123Adapter) GetVolume() float64 {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	return m.volume
}

// 内部方法，获取当前播放信息
func (m *MPG123Adapter) getPlaybackInfo() audioplayer.PlaybackInfo {

	m.playlistMutex.RLock()
	currentSource := m.source
	m.playlistMutex.RUnlock()

	info := audioplayer.PlaybackInfo{
		Status:    m.status,
		Position:  m.position,
		Duration:  m.duration,
		Volume:    m.volume,
		IsLooping: false,
		Error:     "",
	}

	if currentSource != nil {
		info.Source = currentSource
		logger.SystemDebug("播放信息中包含源文件",
			zap.Any("source", currentSource))
	}

	return info
}

// GetPlaybackInfo 获取当前播放信息
func (m *MPG123Adapter) GetPlaybackInfo() audioplayer.PlaybackInfo {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	return m.getPlaybackInfo()
}

// AddToPlaylist 添加音频到播放列表
func (m *MPG123Adapter) AddToPlaylist(source audioplayer.AudioSource) error {
	m.playlistMutex.Lock()
	defer m.playlistMutex.Unlock()

	// 复制AudioSource到新的对象
	sourceCopy := source

	// 添加到播放列表
	m.playlist = append(m.playlist, &sourceCopy)

	return nil
}

// RemoveFromPlaylist 从播放列表移除指定索引的音频
func (m *MPG123Adapter) RemoveFromPlaylist(index int) error {
	m.playlistMutex.Lock()
	defer m.playlistMutex.Unlock()

	if index < 0 || index >= len(m.playlist) {
		return fmt.Errorf("播放列表索引越界: %d", index)
	}

	// 移除指定索引的项
	m.playlist = append(m.playlist[:index], m.playlist[index+1:]...)

	return nil
}

// ClearPlaylist 清空播放列表
func (m *MPG123Adapter) ClearPlaylist() error {
	m.playlistMutex.Lock()
	defer m.playlistMutex.Unlock()

	m.playlist = make([]*audioplayer.AudioSource, 0)
	return nil
}

// GetPlaylist 获取当前播放列表
func (m *MPG123Adapter) GetPlaylist() ([]audioplayer.AudioSource, error) {
	m.playlistMutex.RLock()
	defer m.playlistMutex.RUnlock()

	result := make([]audioplayer.AudioSource, len(m.playlist))
	for i, source := range m.playlist {
		result[i] = *source // 复制对象
	}

	return result, nil
}

// PlayNext 播放下一首
func (m *MPG123Adapter) PlayNext(ctx context.Context) error {
	m.playlistMutex.Lock()
	// 先获取播放列表状态，然后在函数结束时再解锁
	defer m.playlistMutex.Unlock()

	// 如果播放列表为空，无法播放下一首
	if len(m.playlist) == 0 {
		return fmt.Errorf("播放列表为空")
	}

	// 获取当前播放的音频路径
	currentPath := ""
	m.mutex.Lock()
	if m.source != nil {
		currentPath = m.source.Path
	}
	m.mutex.Unlock()

	// 查找当前项在播放列表中的位置
	currentIndex := -1
	for i, src := range m.playlist {
		if src.Path == currentPath {
			currentIndex = i
			break
		}
	}

	// 找到下一首要播放的音频
	var nextSource *audioplayer.AudioSource
	if currentIndex == -1 || currentIndex >= len(m.playlist)-1 {
		// 当前项不在播放列表或是最后一项，从头开始播放
		nextSource = m.playlist[0]
	} else {
		// 播放下一项
		nextSource = m.playlist[currentIndex+1]
	}

	// 解锁playlist，因为Play方法可能会请求这个锁
	m.playlistMutex.Unlock()

	// 播放下一首
	err := m.Play(ctx, *nextSource)

	// 重新锁定playlist
	m.playlistMutex.Lock()
	return err
}

// PlayPrevious 播放上一首
func (m *MPG123Adapter) PlayPrevious(ctx context.Context) error {
	m.playlistMutex.Lock()
	// 先获取播放列表状态，然后在函数结束时再解锁
	defer m.playlistMutex.Unlock()

	// 如果播放列表为空，无法播放上一首
	if len(m.playlist) == 0 {
		return fmt.Errorf("播放列表为空")
	}

	// 获取当前播放的音频路径
	currentPath := ""
	m.mutex.Lock()
	if m.source != nil {
		currentPath = m.source.Path
	}
	m.mutex.Unlock()

	// 查找当前项在播放列表中的位置
	currentIndex := -1
	for i, src := range m.playlist {
		if src.Path == currentPath {
			currentIndex = i
			break
		}
	}

	// 找到上一首要播放的音频
	var prevSource *audioplayer.AudioSource
	if currentIndex <= 0 {
		// 当前项不在播放列表、是第一项或未找到，播放最后一首
		prevSource = m.playlist[len(m.playlist)-1]
	} else {
		// 播放上一项
		prevSource = m.playlist[currentIndex-1]
	}

	// 解锁playlist，因为Play方法可能会请求这个锁
	m.playlistMutex.Unlock()

	// 播放上一首
	err := m.Play(ctx, *prevSource)

	// 重新锁定playlist
	m.playlistMutex.Lock()
	return err
}

// GetSupportedFormats 获取支持的音频格式
func (m *MPG123Adapter) GetSupportedFormats() []audioplayer.AudioFormat {
	return m.supportedFormats
}

// RegisterEventHandler 注册事件处理器
func (m *MPG123Adapter) RegisterEventHandler(eventType audioplayer.PlaybackEventType, handler audioplayer.PlaybackEventHandler) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.eventHandlers == nil {
		m.eventHandlers = make(map[audioplayer.PlaybackEventType][]audioplayer.PlaybackEventHandler)
	}

	m.eventHandlers[eventType] = append(m.eventHandlers[eventType], handler)
}

// UnregisterEventHandler 注销事件处理器
func (m *MPG123Adapter) UnregisterEventHandler(eventType audioplayer.PlaybackEventType, handler audioplayer.PlaybackEventHandler) {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if m.eventHandlers == nil {
		return
	}

	handlers, exists := m.eventHandlers[eventType]
	if !exists {
		return
	}

	// 找到并移除指定的处理器
	for i, h := range handlers {
		if fmt.Sprintf("%p", h) == fmt.Sprintf("%p", handler) {
			m.eventHandlers[eventType] = append(handlers[:i], handlers[i+1:]...)
			break
		}
	}
}

// Initialize 初始化播放器
func (m *MPG123Adapter) Initialize() error {
	// 在第一次Play时才会实际初始化mpg123
	return nil
}

// Close 关闭播放器并释放资源
func (m *MPG123Adapter) Close() error {
	logger.SystemInfo("正在关闭MPG123播放器...")

	m.mutex.Lock()
	defer m.mutex.Unlock()

	// 先发送停止信号，防止goroutine泄漏
	if m.stopChan != nil {
		logger.SystemDebug("发送停止信号到监控线程")
		select {
		case m.stopChan <- struct{}{}:
			// 成功发送停止信号
		default:
			// 通道已关闭或已满，忽略
		}
		close(m.stopChan)
		m.stopChan = nil
	}

	if m.cmd != nil && m.cmd.Process != nil {
		// 先发送停止命令
		logger.SystemDebug("发送QUIT命令到mpg123进程")
		if m.stdin != nil {
			// 尝试发送QUIT命令，但不阻塞太久
			quitDone := make(chan struct{})
			go func() {
				defer close(quitDone)
				_ = m.sendCommand("QUIT")
			}()

			// 等待最多1秒
			select {
			case <-quitDone:
				// QUIT命令发送成功
			case <-time.After(1 * time.Second):
				logger.SystemWarn("发送QUIT命令超时")
			}
		}

		// 关闭stdin
		if m.stdin != nil {
			logger.SystemDebug("关闭mpg123标准输入")
			m.stdin.Close()
			m.stdin = nil
		}

		// 关闭stdout
		if m.stdout != nil {
			logger.SystemDebug("关闭mpg123标准输出")
			m.stdout = nil
		}

		// 关闭stderr
		if m.stderr != nil {
			logger.SystemDebug("关闭mpg123标准错误")
			m.stderr = nil
		}

		// 等待进程结束，但设置超时
		logger.SystemDebug("等待mpg123进程结束")
		doneCh := make(chan error, 1)
		go func() {
			doneCh <- m.cmd.Wait()
		}()

		// 等待最多2秒
		var err error
		select {
		case err = <-doneCh:
			if err != nil {
				logger.SystemError("mpg123进程结束出错", zap.Error(err))
			} else {
				logger.SystemInfo("mpg123进程已正常退出")
			}
		case <-time.After(2 * time.Second):
			logger.SystemWarn("等待mpg123进程结束超时，尝试强制结束进程")
			// 强制杀掉进程
			if m.cmd.Process != nil {
				if killErr := m.cmd.Process.Kill(); killErr != nil {
					logger.SystemError("强制杀掉mpg123进程失败", zap.Error(killErr))
				} else {
					logger.SystemInfo("已强制终止mpg123进程")
				}
			}
		}

		m.cmd = nil
	}

	// 清空状态
	m.status = audioplayer.StatusStopped
	m.source = nil
	m.position = 0
	m.duration = 0

	logger.SystemInfo("MPG123播放器已完全关闭")
	return nil
}

// 使用mpg123 -v获取时长
func getMp3DurationWithMpg123Verbose(filePath string) (float64, error) {
	// 使用索引和详细输出模式，这样可以获取更准确的时长信息
	cmd := exec.Command("mpg123", "--skip-printing-frames", "-n1", "-i", "-v", filePath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, fmt.Errorf("执行mpg123命令失败: %v", err)
	}

	// 解析输出，查找时长信息
	outputStr := string(output)
	logger.SystemDebug("MPG123-verbose输出", zap.String("output", outputStr))

	// 尝试直接匹配播放行的格式 "0000+0000  00:00.00+02:37.02"
	playLineRegex := regexp.MustCompile(`\d+\+\d+\s+\d+:\d+\.\d+\+(\d+):(\d+)\.(\d+)`)
	playMatches := playLineRegex.FindStringSubmatch(outputStr)
	if len(playMatches) >= 4 {
		minutes, _ := strconv.Atoi(playMatches[1])
		seconds, _ := strconv.Atoi(playMatches[2])
		centiseconds, _ := strconv.Atoi(playMatches[3])

		duration := float64(minutes*60) + float64(seconds) + float64(centiseconds)/100.0
		logger.SystemDebug("从播放行匹配到时长",
			zap.String("match", playMatches[0]),
			zap.Float64("duration", duration))
		return duration, nil
	}

	// 如果直接匹配播放行失败，尝试其他格式
	patterns := []string{
		`\[(\d+):(\d+)\.(\d+)\]`,              // [mm:ss.ms]
		`Length:\s+(\d+):(\d+)\.(\d+)`,        // Length: mm:ss.ms
		`(\d+) minute\(s\) (\d+) second\(s\)`, // X minute(s) Y second(s)
		`Playing time: (\d+):(\d+)\.(\d+)`,    // Playing time: mm:ss.ms
		`Time: (\d+):(\d+)\.(\d+)`,            // Time: mm:ss.ms
	}

	for _, pattern := range patterns {
		regex := regexp.MustCompile(pattern)
		matches := regex.FindStringSubmatch(outputStr)

		if len(matches) >= 4 {
			minutes, _ := strconv.Atoi(matches[1])
			seconds, _ := strconv.Atoi(matches[2])
			milliseconds, _ := strconv.Atoi(matches[3])

			// 根据正则模式的不同，小数部分可能是毫秒或百分之一秒
			var duration float64
			if pattern == `\[(\d+):(\d+)\.(\d+)\]` || pattern == `Length:\s+(\d+):(\d+)\.(\d+)` {
				// 假设这个格式下小数部分是百分之一秒
				duration = float64(minutes*60+seconds) + float64(milliseconds)/100.0
			} else {
				// 假设默认是毫秒
				duration = float64(minutes*60+seconds) + float64(milliseconds)/1000.0
			}

			logger.SystemDebug("从mpg123-verbose匹配到时长",
				zap.String("pattern", pattern),
				zap.Float64("duration", duration))
			return duration, nil
		}
	}

	// 尝试查找比特率信息并使用文件大小估算
	bitrateRegex := regexp.MustCompile(`(\d+) kb/s`)
	bitrateMatches := bitrateRegex.FindStringSubmatch(outputStr)
	if len(bitrateMatches) >= 2 {
		bitrate, err := strconv.Atoi(bitrateMatches[1])
		if err == nil && bitrate > 0 {
			// 获取文件大小
			fileInfo, err := os.Stat(filePath)
			if err == nil {
				// 估算时长
				sizeBytes := fileInfo.Size()
				// 减去估计的标签大小
				estimatedTagSize := int64(10 * 1024)
				if sizeBytes > estimatedTagSize {
					sizeBytes -= estimatedTagSize
				}
				estimatedDuration := float64(sizeBytes) / (float64(bitrate) * 1000 / 8)

				logger.SystemDebug("从比特率和文件大小估算时长",
					zap.Int("bitrate", bitrate),
					zap.Int64("fileSize", fileInfo.Size()),
					zap.Float64("estimatedDuration", estimatedDuration))
				return estimatedDuration, nil
			}
		}
	}

	return 0, fmt.Errorf("无法从mpg123-verbose输出中解析时长")
}

// 使用mpg123 --frames -n获取总帧数，估算时长
func getMp3DurationWithMpg123Frames(filePath string) (float64, error) {
	// 添加索引选项 -i 用于获取完整的帧信息
	cmd := exec.Command("mpg123", "-i", "--frames", "-n", filePath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, fmt.Errorf("执行mpg123 --frames命令失败: %v", err)
	}

	outputStr := string(output)
	logger.SystemDebug("MPG123-frames输出", zap.String("output", outputStr))

	// 查找帧信息
	regex := regexp.MustCompile(`(\d+) MPEG frames decoded`)
	matches := regex.FindStringSubmatch(outputStr)
	if len(matches) >= 2 {
		frames, err := strconv.Atoi(matches[1])
		if err == nil && frames > 0 {
			// 估算时长，基于MP3典型帧率
			duration := float64(frames) / 38.0 // 假设每秒约38帧
			logger.SystemDebug("从帧数估算时长",
				zap.Int("frames", frames),
				zap.Float64("duration", duration))
			return duration, nil
		}
	}

	// 尝试获取时长信息的更多方式
	durationPatterns := []string{
		`\[(\d+):(\d+)\.(\d+)\]`,           // [mm:ss.ms]
		`Length:\s+(\d+):(\d+)\.(\d+)`,     // Length: mm:ss.ms
		`Playing time: (\d+):(\d+)\.(\d+)`, // Playing time: mm:ss.ms
	}

	for _, pattern := range durationPatterns {
		regex := regexp.MustCompile(pattern)
		matches := regex.FindStringSubmatch(outputStr)

		if len(matches) >= 4 {
			minutes, _ := strconv.Atoi(matches[1])
			seconds, _ := strconv.Atoi(matches[2])
			milliseconds, _ := strconv.Atoi(matches[3])

			duration := float64(minutes*60+seconds) + float64(milliseconds)/1000.0
			logger.SystemDebug("从mpg123-frames的输出中匹配到时长",
				zap.String("pattern", pattern),
				zap.Float64("duration", duration))
			return duration, nil
		}
	}

	return 0, fmt.Errorf("无法从mpg123-frames输出中获取时长信息")
}

// 新增：使用mpg123专门的索引模式获取时长
func getMp3DurationWithMpg123Index(filePath string) (float64, error) {
	// 使用 -i 索引选项和 --index-size 设置较大的索引缓冲区，以便更准确地扫描文件
	cmd := exec.Command("mpg123", "-i", "--index-size", "8192", "--skip-printing-frames", "-n1", "-v", filePath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, fmt.Errorf("执行mpg123索引命令失败: %v", err)
	}

	outputStr := string(output)
	logger.SystemDebug("MPG123-index输出", zap.String("output", outputStr))

	// 查找时长信息
	patterns := []string{
		`\[(\d+):(\d+)\.(\d+)\]`,           // [mm:ss.ms]
		`Length:\s+(\d+):(\d+)\.(\d+)`,     // Length: mm:ss.ms
		`Playing time: (\d+):(\d+)\.(\d+)`, // Playing time: mm:ss.ms
		`Time: (\d+):(\d+)\.(\d+)`,         // Time: mm:ss.ms
	}

	for _, pattern := range patterns {
		regex := regexp.MustCompile(pattern)
		matches := regex.FindStringSubmatch(outputStr)

		if len(matches) >= 4 {
			minutes, _ := strconv.Atoi(matches[1])
			seconds, _ := strconv.Atoi(matches[2])
			milliseconds, _ := strconv.Atoi(matches[3])

			duration := float64(minutes*60+seconds) + float64(milliseconds)/1000.0
			logger.SystemDebug("从mpg123-index匹配到时长",
				zap.String("pattern", pattern),
				zap.Float64("duration", duration))
			return duration, nil
		}
	}

	return 0, fmt.Errorf("无法从mpg123-index输出中解析时长")
}

// 新增：使用mpg123直接播放模式获取时长
func getMp3DurationWithMpg123Direct(filePath string) (float64, error) {
	// 直接使用mpg123的播放模式，但加入-t测试选项避免实际播放声音，配合-v获取详细信息
	cmd := exec.Command("mpg123", "-t", "-v", "--no-control", filePath)
	output, err := cmd.CombinedOutput()
	if err != nil && !strings.Contains(err.Error(), "exit status") {
		// mpg123即使成功完成测试模式也会返回非零状态码，所以我们忽略exit status错误
		return 0, fmt.Errorf("执行mpg123直接模式命令失败: %v", err)
	}

	outputStr := string(output)
	logger.SystemDebug("MPG123-direct输出", zap.String("output", outputStr))

	// 匹配播放行的格式 "0000+0000  00:00.00+02:37.02"
	playLineRegex := regexp.MustCompile(`\d+\+\d+\s+\d+:\d+\.\d+\+(\d+):(\d+)\.(\d+)`)
	playMatches := playLineRegex.FindStringSubmatch(outputStr)
	if len(playMatches) >= 4 {
		minutes, _ := strconv.Atoi(playMatches[1])
		seconds, _ := strconv.Atoi(playMatches[2])
		centiseconds, _ := strconv.Atoi(playMatches[3])

		duration := float64(minutes*60) + float64(seconds) + float64(centiseconds)/100.0
		logger.SystemDebug("从播放行匹配到时长",
			zap.String("match", playMatches[0]),
			zap.Float64("duration", duration))
		return duration, nil
	}

	// 尝试匹配总帧数和帧率信息
	framesRegex := regexp.MustCompile(`(\d+) frames decoded`)
	framesMatches := framesRegex.FindStringSubmatch(outputStr)

	rateRegex := regexp.MustCompile(`(\d+\.\d+) fps`)
	rateMatches := rateRegex.FindStringSubmatch(outputStr)

	if len(framesMatches) >= 2 && len(rateMatches) >= 2 {
		frames, _ := strconv.Atoi(framesMatches[1])
		rate, _ := strconv.ParseFloat(rateMatches[1], 64)

		if frames > 0 && rate > 0 {
			duration := float64(frames) / rate
			logger.SystemDebug("从帧数和帧率估算时长",
				zap.Int("frames", frames),
				zap.Float64("rate", rate),
				zap.Float64("duration", duration))
			return duration, nil
		}
	}

	// 尝试查找比特率信息并使用文件大小估算
	bitrateRegex := regexp.MustCompile(`(\d+) kb/s`)
	bitrateMatches := bitrateRegex.FindStringSubmatch(outputStr)
	if len(bitrateMatches) >= 2 {
		bitrate, err := strconv.Atoi(bitrateMatches[1])
		if err == nil && bitrate > 0 {
			// 获取文件大小
			fileInfo, err := os.Stat(filePath)
			if err == nil {
				// 估算时长
				sizeBytes := fileInfo.Size()
				// 减去估计的标签大小
				estimatedTagSize := int64(10 * 1024)
				if sizeBytes > estimatedTagSize {
					sizeBytes -= estimatedTagSize
				}
				estimatedDuration := float64(sizeBytes) / (float64(bitrate) * 1000 / 8)

				logger.SystemDebug("从比特率和文件大小估算时长",
					zap.Int("bitrate", bitrate),
					zap.Int64("fileSize", fileInfo.Size()),
					zap.Float64("estimatedDuration", estimatedDuration))
				return estimatedDuration, nil
			}
		}
	}

	return 0, fmt.Errorf("无法从mpg123-direct输出中获取时长信息")
}

// 获取MP3文件信息
func getMP3Info(filePath string) (mp3Info, error) {
	info := mp3Info{}

	// 使用多种方法尝试获取时长信息
	methods := []struct {
		name    string
		tryFunc func(string) (float64, error)
	}{
		{"mpg123-direct", getMp3DurationWithMpg123Direct}, // 新增的直接播放模式
		{"mpg123-index", getMp3DurationWithMpg123Index},   // 索引方法
		{"mpg123-verbose", getMp3DurationWithMpg123Verbose},
		{"mpg123-frames", getMp3DurationWithMpg123Frames},
		{"ffprobe", getMp3DurationWithFfprobe},
		{"soxi", getMp3DurationWithSoxi},
	}

	var lastErr error
	for _, method := range methods {
		logger.SystemDebug("尝试使用方法获取MP3时长", zap.String("method", method.name))
		duration, err := method.tryFunc(filePath)

		if err == nil && duration > 0 {
			info.duration = duration
			logger.SystemInfo("成功获取MP3时长",
				zap.String("method", method.name),
				zap.Float64("duration", duration),
				zap.String("file", filePath))
			return info, nil
		}

		// 检查是否为工具不存在的错误
		if strings.Contains(err.Error(), "executable file not found") {
			logger.SystemDebug("工具不存在，跳过",
				zap.String("method", method.name),
				zap.Error(err))
		} else {
			lastErr = err
			logger.SystemDebug("获取时长失败，尝试下一种方法",
				zap.String("method", method.name),
				zap.Error(err))
		}
	}

	// 如果所有方法都失败，记录警告并返回合理的默认值
	logger.SystemWarn("所有方法获取MP3时长均失败，使用默认值",
		zap.String("file", filePath),
		zap.Error(lastErr))

	// 使用默认时长而不是返回错误，这样至少有个合理的值
	info.duration = 60.0 * 10 // 默认3分钟
	return info, nil
}

// 使用ffprobe获取时长
func getMp3DurationWithFfprobe(filePath string) (float64, error) {
	cmd := exec.Command("ffprobe", "-i", filePath, "-show_entries", "format=duration", "-v", "quiet", "-of", "csv=p=0")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, fmt.Errorf("执行ffprobe命令失败: %v", err)
	}

	// 解析输出
	durationStr := strings.TrimSpace(string(output))
	logger.SystemDebug("ffprobe输出", zap.String("output", durationStr))

	duration, err := strconv.ParseFloat(durationStr, 64)
	if err != nil {
		return 0, fmt.Errorf("解析ffprobe时长失败: %v", err)
	}

	return duration, nil
}

// 使用soxi获取时长
func getMp3DurationWithSoxi(filePath string) (float64, error) {
	cmd := exec.Command("soxi", "-D", filePath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, fmt.Errorf("执行soxi命令失败: %v", err)
	}

	// 解析输出
	durationStr := strings.TrimSpace(string(output))
	logger.SystemDebug("soxi输出", zap.String("output", durationStr))

	duration, err := strconv.ParseFloat(durationStr, 64)
	if err != nil {
		return 0, fmt.Errorf("解析soxi时长失败: %v", err)
	}

	return duration, nil
}

// GetCurrentFile 获取当前播放的文件名
func (m *MPG123Adapter) GetCurrentFile() string {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	// 优先使用从ID3解析的名称
	if m.currentFileName != "" {
		return m.currentFileName
	}

	// 回退到源文件名
	if m.source != nil && m.source.Name != "" {
		return m.source.Name
	}

	// 最后回退到文件路径
	if m.currentFile != "" {
		// 提取文件名部分
		parts := strings.Split(m.currentFile, "/")
		return parts[len(parts)-1]
	}

	return "未知文件"
}

// monitorError 监控mpg123的标准错误输出
func (m *MPG123Adapter) monitorError() {
	if m.stderr == nil {
		logger.SystemError("标准错误流为空，无法监控")
		return
	}

	logger.SystemInfo("开始监控mpg123错误输出")
	defer logger.SystemInfo("停止监控mpg123错误输出")

	scanner := bufio.NewScanner(m.stderr)
	// 使用更大的缓冲区，避免长行被截断
	buf := make([]byte, 64*1024)
	scanner.Buffer(buf, len(buf))

	for scanner.Scan() {
		line := scanner.Text()

		// 检查是否包含重要错误关键词
		if strings.Contains(line, "error") ||
			strings.Contains(line, "fail") ||
			strings.Contains(line, "invalid") {
			logger.SystemError("mpg123错误输出", zap.String("output", line))
		} else {
			// 其他输出作为调试信息
			logger.SystemDebug("mpg123错误流输出", zap.String("output", line))
		}

		// 如果错误指示播放出错，尝试触发播放错误事件
		if strings.Contains(line, "cannot open") ||
			strings.Contains(line, "failed to open") ||
			strings.Contains(line, "read error") {
			m.mutex.Lock()
			m.status = audioplayer.StatusError
			m.triggerEvent(audioplayer.EventPlaybackError)
			m.mutex.Unlock()
		}
	}

	if err := scanner.Err(); err != nil {
		logger.SystemError("读取mpg123标准错误输出时出错", zap.Error(err))
	}
}
